package cmp.compile.panels;

/*****************************************************
 * Species panel of the main window including the table, which contains all species variables
 * (even if not displayed)
 * The object is created in the CompilePanel
 * The buttons Add, Edit, Remove, Create Database are created 
 * and actions attached (all but Create Database).
 * Create Database action is called in CompileMain.compileSelectListener
 * 
 * NOTE: setting values is very complicated!!
 * 
 * XXX How about this:
 * 	Each panel registers itself with Global.register("SpeciesPanel", this);
 *  All button listeners are directly below the button definition.
 *  As part of the listener's action, it calls Global.turnOffAllBut("SpeciesPanel")
 *  	which calls for all panels their 'disable' method
 */
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentEvent;

import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSeparator;
import javax.swing.JTable;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.plaf.ScrollBarUI;
import javax.swing.plaf.basic.BasicScrollBarUI;
import javax.swing.table.AbstractTableModel;

import cmp.main.Globals;

public class SpeciesPanel extends JPanel {
	private static final long serialVersionUID = -7854401073530999670L;
	
	public SpeciesPanel(CompilePanel parentPanel) {
		theParentPanel = parentPanel;
		
		theTable = new SpeciesTable();
		theTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
			public void valueChanged(ListSelectionEvent arg0) {
				updateTableButtons();
			}
		});
		
		lblSpecies = new JLabel("1. single TCW databases");

		/** Add button on 1st section of Main panel
		 *  The values are stored in EditSpeciesPanel and the Table in CompilePanel?
		 ***/
		btnAdd = new JButton("Add");
		btnAdd.setBackground(Globals.MENUCOLOR);
		btnAdd.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				theParentPanel.getEditSpeciesPanel().setHost("");
				theParentPanel.getEditSpeciesPanel().setDBName("");
				theParentPanel.getEditSpeciesPanel().setAssemblyName("");
				theParentPanel.getEditSpeciesPanel().setPeptideDB(false);
				theParentPanel.getEditSpeciesPanel().setProteinFile("");
				theParentPanel.getEditSpeciesPanel().setSMATFile("");
				theParentPanel.getEditSpeciesPanel().setRemark("");
				theParentPanel.getEditSpeciesPanel().setPrefix("");
				theParentPanel.getEditSpeciesPanel().setGenerateProteinFile();
				theParentPanel.getEditSpeciesPanel().setEditMode(false);
				theParentPanel.getEditSpeciesPanel().setVisible(true);
				theParentPanel.getEditSpeciesPanel().setLoaded(false);
				theParentPanel.setMainPanelVisible(false);
				theParentPanel.getEditSpeciesPanel().updateFileSelection();
			}
		});
		/** 
		 * Edit button on 1st section of Main panel
		 */
		btnEdit = new JButton("Edit");
		btnEdit.setBackground(Globals.MENUCOLOR);
		btnEdit.setEnabled(false);
		btnEdit.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				int row = theTable.getSelectedRow();
				theParentPanel.getEditSpeciesPanel().setHost(theTable.getHostNameAt(row));
				theParentPanel.getEditSpeciesPanel().setAssemblyName(theTable.getAssemblyNameAt(row));
				theParentPanel.getEditSpeciesPanel().setPeptideDB(theTable.isPeptideDB(row));
				theParentPanel.getEditSpeciesPanel().setProteinFile(theTable.getProteinFileAt(row));
				theParentPanel.getEditSpeciesPanel().setSMATFile(theTable.getSMATFileAt(row));
				theParentPanel.getEditSpeciesPanel().setRemark(theTable.getRemarkAt(row));
				theParentPanel.getEditSpeciesPanel().setDBName(theTable.getDBNameAt(row));
				theParentPanel.getEditSpeciesPanel().setPrefix(theTable.getPrefixAt(row));
				theParentPanel.getEditSpeciesPanel().setGenerateProteinFile(theTable.isGenerateProteinFile(row));
				theParentPanel.getEditSpeciesPanel().setPeptideDB(theTable.isPeptideDB(row));
				theParentPanel.getEditSpeciesPanel().setEditMode(true);
				theParentPanel.getEditSpeciesPanel().setVisible(true);
				theParentPanel.getEditSpeciesPanel().setLoaded(theParentPanel.isDatabaseLoaded());
				theParentPanel.setMainPanelVisible(false);
				theParentPanel.getEditSpeciesPanel().updateFileSelection();
			}
		});
		btnRemove = new JButton("Remove");
		btnRemove.setBackground(Globals.BGCOLOR);
		btnRemove.setEnabled(false); 
		btnRemove.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				theTable.removeRow(theTable.getSelectedRow());
				((AbstractTableModel)theTable.getModel()).fireTableDataChanged();
			}
		});
		
		Dimension d = btnRemove.getPreferredSize();
		btnRemove.setMaximumSize(d);
		btnRemove.setMinimumSize(d);
		btnEdit.setMaximumSize(d);
		btnEdit.setMinimumSize(d);
		btnAdd.setMaximumSize(d);
		btnAdd.setMinimumSize(d);
		
		setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
		setBackground(Globals.BGCOLOR);
		
		sPane = new JScrollPane(theTable);
		sPane.setBackground(Globals.BGCOLOR);
		sPane.getViewport().setBackground(Globals.BGCOLOR);
		theTable.getTableHeader().setBackground(Globals.BGCOLOR);
		ScrollBarUI tUI = new BasicScrollBarUI() {
		    protected JButton createDecreaseButton(int orientation) {
		        JButton button = super.createDecreaseButton(orientation);
		        button.setBackground(Globals.BGCOLOR);
		        return button;
		    }

		    protected JButton createIncreaseButton(int orientation) {
		        JButton button = super.createIncreaseButton(orientation);
		        button.setBackground(Globals.BGCOLOR);
		        return button;
		    }
		};

		sPane.getHorizontalScrollBar().setBackground(Globals.BGCOLOR);
		sPane.getVerticalScrollBar().setBackground(Globals.BGCOLOR);
		sPane.getHorizontalScrollBar().setUI(tUI);
		sPane.getVerticalScrollBar().setUI(tUI);
				
		buttonPanel = CompilePanel.getPanel(false);
		buttonPanel.add(Box.createVerticalStrut(15));
		buttonPanel.add(btnAdd);
		buttonPanel.add(Box.createVerticalStrut(5));
		buttonPanel.add(btnEdit);
		buttonPanel.add(Box.createVerticalStrut(5));
		buttonPanel.add(btnRemove);
		buttonPanel.add(Box.createVerticalStrut(15));
		
		buttonPanel.setMaximumSize(buttonPanel.getPreferredSize());
		buttonPanel.setMinimumSize(buttonPanel.getPreferredSize());
		
		btnCreateDatabase = new JButton("Build Database");
		btnCreateDatabase.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				if (theParentPanel.isValid()) { 
					theParentPanel.saveCPAVE();
					theParentPanel.getParentFrame().getParentMain().createDatabase();
					theParentPanel.getMethodPanel().clearAllLoaded();
					theParentPanel.getMethodPanel().validateMethods(true);
					theParentPanel.getBlastPanel().editPanel.fillEmptyFieldsWithDefaults();
				}
			}
		});
		
		mainPanel = CompilePanel.getPanel(false);
		
		JPanel row = CompilePanel.getPanel(true);
		row.add(sPane);
		row.add(Box.createHorizontalStrut(5));
		row.add(buttonPanel);
		d = row.getMaximumSize();
		d.height = buttonPanel.getMaximumSize().height;
		row.setMaximumSize(d);
		
		mainPanel.add(Box.createVerticalStrut(10));
		mainPanel.add(lblSpecies);
		mainPanel.add(Box.createVerticalStrut(10));
		mainPanel.add(row);
		add(mainPanel);
				
		add(Box.createVerticalStrut(10));
		add(btnCreateDatabase);			
		add(Box.createVerticalStrut(10));
		add(new JSeparator());
	}
	
	public String getPrefixForAssembly(String assembly) {
		for(int x=0; x<theTable.getRowCount(); x++) {
			if(((String)theTable.getValueAt(x, 0)).equals(assembly)) {
				return (String)theTable.getValueAt(x, 1);
			}
		}
		return null;
	}
	
	public int getSelectedRow() { return theTable.getSelectedRow(); }
	
	public void setCreateDatabaseEnabled(boolean enabled) { btnCreateDatabase.setEnabled(enabled); }
	
	public void resizeEvent(ComponentEvent e) {}
	
	public void clearData() {theTable.clearTable();}
	
	public int getNumRows() { return theTable.getRowCount(); }
	public String getHostAt(int row) { return theTable.getHostNameAt(row); }
	public String getAssemNameAt(int row) { return theTable.getAssemblyNameAt(row); }
	public String getDBNameAt(int row) { return theTable.getDBNameAt(row); }
	public String getPrefixAt(int row) { return theTable.getPrefixAt(row); }
	public String getProteinFileAt(int row) { return theTable.getProteinFileAt(row); }
	public String getSMATFileAt(int row) { return theTable.getSMATFileAt(row); }
	public String getRemarkAt(int row) { return theTable.getRemarkAt(row); }
	public boolean isGenerateProteinFileAt(int row) { return theTable.isGenerateProteinFile(row); }
	public boolean isPeptideDBAt(int row) { return theTable.isPeptideDB(row); }
	
	// CAS these are not used?
	public void setHostAt(int row, String host) { theTable.setHostNameAt(row, host); }
	public void setAssemNameAt(int row, String assembly) { theTable.setAssemblyNameAt(row, assembly); }
	public void setDBName(int row, String dbName) { theTable.setDBNameAt(row, dbName); }
	public void setPrefixAt(int row, String prefix) { theTable.setPrefixAt(row, prefix); }
	public void setProteinFileAt(int row, String proteinFile) { theTable.setProteinFileAt(row, proteinFile); }
	public void setSMATFileAt(int row, String SMATFile) { theTable.setSMATFileAt(row, SMATFile); }
	public void setRemarkAt(int row, String remark) { theTable.setRemarkAt(row, remark); }
	public void setIsGenerateProteinFileAt(int row, boolean generateProteinFile) { theTable.setGenerateProteinFile(row, generateProteinFile); }
	public void setIsPeptideDBAt(int row, boolean isPeptideDB) { theTable.setIsPeptideDB(row, isPeptideDB); }
	
	public void addRow(String host, String dbName, String prefix, String assembly, String proteinFile, String SMATFile, 
			String remark, boolean generateProteinFile, boolean isPeptide) {
		theTable.addRow(host, dbName, prefix, assembly, proteinFile, SMATFile, remark, generateProteinFile, isPeptide);
	}
	
	public void setRow(int row, String host, String dbName, String prefix, String assembly, String proteinFile, String SMATFile, 
			String remark, boolean generateProteinFile, boolean isPeptide) {
		theTable.setRow(row, host, dbName, prefix, assembly, proteinFile, SMATFile, remark, generateProteinFile, isPeptide);
	}
	
	public void updateTable() {
		((AbstractTableModel)theTable.getModel()).fireTableDataChanged();
	}
	
	// Called from CompilePanel
	public void setProjectSelected(boolean selected) {
		btnAdd.setEnabled(selected);
		btnEdit.setEnabled(selected);
		btnRemove.setEnabled(selected);
		theTable.setEnabled(selected);
		btnCreateDatabase.setEnabled(selected);
		
		if(selected)
			updateTableButtons();
		else
			clearData();
	}
	private void updateTableButtons() {
		if(theTable.getSelectedRowCount() > 0) {
			btnEdit.setEnabled(true);
		}
		else {
			btnEdit.setEnabled(false);
		}

		if(theTable.getSelectedRowCount() > 0) { // CAS 3/30/15 && !theParentPanel.isDatabaseLoaded()) {
			btnRemove.setEnabled(true);
		}
		else {
			btnRemove.setEnabled(false);
		}
	}
	private CompilePanel theParentPanel = null; 

	/***************************************************************************
	 * The Table class
	 */
	private SpeciesTable theTable = null;
	private JScrollPane sPane = null;
	private JPanel buttonPanel = null;
	private JPanel mainPanel = null;
	private JButton btnAdd = null;
	private JButton btnEdit = null;
	private JButton btnRemove = null;
	private JLabel lblSpecies = null;
	private JButton btnCreateDatabase = null;
	
	private class SpeciesTable extends JTable {
		private static final long serialVersionUID = -4484804841714567031L;

		private final String [] COLUMN_NAMES = { "singleTCW", "Prefix", "SMAT/Protein File", "Remark" };

		public SpeciesTable() {
	    		theModel = new SpeciesTableModel();
	    	
	        setAutoCreateColumnsFromModel( true );
	       	setColumnSelectionAllowed( false );
	       	setCellSelectionEnabled( false );
	       	setRowSelectionAllowed( true );
	       	setShowHorizontalLines( false );
	       	setShowVerticalLines( true );	
	       	setIntercellSpacing ( new Dimension ( 1, 0 ) );
	       	setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
	       	setOpaque(true);

	       	setModel(theModel);
		}
		
		public int getRowCount() {
			return theModel.getRowCount(); 
		}
		
		public void addRow(String host, String database, String prefix, String assembly, 
				String proteinFile, String SMATFile, String remark, boolean generateProteinFile, boolean isPeptide) {
			theModel.addRow(host, database, prefix, assembly, proteinFile, SMATFile, remark, generateProteinFile, isPeptide);
		}
		
		public void setRow(int row, String host, String database, String prefix, String assembly, 
				String proteinFile, String SMATFile, String remark, boolean generateProteinFile, boolean isPeptide) {
			theModel.setRow(row, host, database, prefix, assembly, proteinFile, SMATFile, remark, generateProteinFile, isPeptide);
		}
		
		public void removeRow(int row) {
			theModel.removeRow(row);
		}
		
		public void clearTable() {
			theModel.clearTable();
			theModel.fireTableDataChanged();
		}
		
		public Object getValueAt(int row, int column) {
			return theModel.getValueAt(row, column);
		}
		
		public String getHostNameAt(int row) { return theModel.getHostAt(row); }
		public String getDBNameAt(int row) { return theModel.getDBNameAt(row); }
		public String getPrefixAt(int row) { return theModel.getPrefixAt(row); }
		public String getAssemblyNameAt(int row) { return theModel.getAssemblyNameAt(row); }
		public String getProteinFileAt(int row) { return theModel.getProteinFileAt(row); }
		public String getSMATFileAt(int row) { return theModel.getSMATFileAt(row); }
		public String getRemarkAt(int row) { return theModel.getRemark(row); }
		public boolean isGenerateProteinFile(int row) { return theModel.isGenerateProteinFileAt(row); }
		public boolean isPeptideDB(int row) { return theModel.isPepTideDB(row); }
		
		public void setHostNameAt(int row, String host) { theModel.setHostAt(row, host); }
		public void setDBNameAt(int row, String database) { theModel.setDatabaseAt(row, database); }
		public void setPrefixAt(int row, String prefix) { theModel.setPrefixAt(row, prefix); }
		public void setAssemblyNameAt(int row, String assembly) { theModel.setAssemblyAt(row, assembly); }
		public void setProteinFileAt(int row, String proteinFile) { theModel.setProteinFileAt(row, proteinFile); }
		public void setSMATFileAt(int row, String SMATFile) { theModel.setSMATFileAt(row, SMATFile); }
		public void setRemarkAt(int row, String remark) { theModel.setRemarkAt(row, remark); }
		public void setGenerateProteinFile(int row, boolean generateProteinFile) { theModel.setGenerateProteinFileAt(row, generateProteinFile); }
		public void setIsPeptideDB(int row, boolean isPeptide) { theModel.setIsPeptideDB(row, isPeptide); }
		
		private SpeciesTableModel theModel = null;
		
		private class SpeciesTableModel extends AbstractTableModel {
			private static final long serialVersionUID = 1757554491364875137L;
			
			public int getColumnCount() { return COLUMN_NAMES.length; }
			public int getRowCount() { return rows.length; }
			public String getColumnName(int pos) { return COLUMN_NAMES[pos]; }

			public Object getValueAt(int row, int column) {
				if(column == 0) return rows[row].getAssemblyName();
				if(column == 1) return rows[row].getPrefix();
				if(column == 2) return getFileAt(row);
				if(column == 3) return rows[row].getRemark();
				if(column == 4) return rows[row].getHost();
				return rows[row].getDBName();
			}
			
			public String getFileAt(int idx) {
				if(rows[idx].isGenerateProteinFile())
					return rows[idx].getSMATFile();
				return rows[idx].getProteinFile();
			}
			
			public void addRow(String host, String database, String prefix, String assembly, 
					String proteinFile, String SMATFile, String remark, boolean generateProteinFile, boolean isPeptide) {
				RowData [] oldTable = rows;
				
				rows = new RowData[oldTable.length + 1];
				for(int x=0; x<oldTable.length; x++)
					rows[x] = new RowData(oldTable[x].getHost(), oldTable[x].getDBName(), 
							oldTable[x].getPrefix(), oldTable[x].getAssemblyName(), 
							oldTable[x].getProteinFile(), oldTable[x].getSMATFile(), 
							oldTable[x].getRemark(), oldTable[x].isGenerateProteinFile(), oldTable[x].isPeptideDB());
				rows[rows.length - 1] = new RowData(host, database, prefix, assembly, proteinFile, 
						SMATFile, remark, generateProteinFile, isPeptide);
			}
			
			public void setRow(int row, String host, String database, String prefix, String assembly, String proteinFile, String SMATFile, String remark, boolean generateProteinFile, boolean isPeptideDB) {
				rows[row].setHost(host);
				rows[row].setDatabase(database);
				rows[row].setPrefix(prefix);
				rows[row].setAssembly(assembly);
				rows[row].setProteinFile(proteinFile);
				rows[row].setSMATFile(SMATFile);
				rows[row].setRemark(remark);
				rows[row].setGenerateProteinFile(generateProteinFile);
				rows[row].setIsPeptide(isPeptideDB);
			}
			
			public void clearTable() {
				rows = new RowData[0];
			}
			
			public void removeRow(int row) {
				RowData [] oldTable = rows;
				int index = 0;
				
				rows = new RowData[oldTable.length - 1];
				for(int x=0; x<oldTable.length; x++) {
					if(x != row) {
						rows[index] = oldTable[x];
						index++;
					}
				}
			}
			
			public String getHostAt(int row) { return rows[row].getHost(); }
			public String getDBNameAt(int row) { return rows[row].getDBName(); }
			public String getPrefixAt(int row) { return rows[row].getPrefix(); }
			public String getAssemblyNameAt(int row) { return rows[row].getAssemblyName(); }
			public String getProteinFileAt(int row) { return rows[row].getProteinFile(); }
			public String getSMATFileAt(int row) { return rows[row].getSMATFile(); }
			public String getRemark(int row) { return rows[row].getRemark(); }
			public boolean isGenerateProteinFileAt(int row) { return rows[row].isGenerateProteinFile(); }
			public boolean isPepTideDB(int row) { return rows[row].isPeptideDB(); }
			
			public void setHostAt(int row, String host) { rows[row].setHost(host); }
			public void setDatabaseAt(int row, String database) { rows[row].setDatabase(database); }
			public void setPrefixAt(int row, String prefix) { rows[row].setPrefix(prefix); }
			public void setAssemblyAt(int row, String assembly) { rows[row].setAssembly(assembly); }
			public void setProteinFileAt(int row, String proteinFile) { rows[row].setProteinFile(proteinFile); }
			public void setSMATFileAt(int row, String SMATFile) { rows[row].setSMATFile(SMATFile); }
			public void setRemarkAt(int row, String remark) { rows[row].setRemark(remark); }
			public void setGenerateProteinFileAt(int row, boolean generate) { rows[row].setGenerateProteinFile(generate); }
			public void setIsPeptideDB(int row, boolean isPeptide) { rows[row].setIsPeptide(isPeptide); }
			
			private RowData [] rows = new RowData[0];
			
			private class RowData {
				public RowData(String host, String database, String prefix, String assembly, String proteinFile, String SMATFile, String remark, boolean generateProteinFile, boolean isPeptideDB) {
					strHost = host;
					strDatabase = database;
					strPrefix = prefix;
					strAssembly = assembly;
					strProteinFile = proteinFile;
					strSMATFile = SMATFile;
					strRemark = remark;
					bGenerateProteinFile = generateProteinFile;
					bPeptideDB = isPeptideDB;
				}
				
				public String getHost() { return strHost; }
				public String getDBName() { return strDatabase; }
				public String getPrefix() { return strPrefix; }
				public String getAssemblyName() { return strAssembly; }
				public String getProteinFile() { return strProteinFile; }
				public String getSMATFile() { return strSMATFile; }
				public String getRemark() { return strRemark; }
				public boolean isGenerateProteinFile() { return bGenerateProteinFile; }
				public boolean isPeptideDB() { return bPeptideDB; }
				
				public void setHost(String name) { strHost = name; }
				public void setDatabase(String database) { strDatabase = database; }
				public void setPrefix(String prefix) { strPrefix = prefix; }
				public void setAssembly(String assembly) { strAssembly = assembly; }
				public void setProteinFile(String file) { strProteinFile = file; }
				public void setSMATFile(String file) { strSMATFile = file; }
				public void setRemark(String remark) { strRemark = remark; }
				public void setGenerateProteinFile(boolean generate) { bGenerateProteinFile = generate; }
				public void setIsPeptide(boolean isPeptide) { bPeptideDB = isPeptide; }

				private String strHost = "";
				private String strDatabase = "";
				private String strPrefix = "";
				private String strAssembly = "";
				private String strProteinFile = "";
				private String strSMATFile = "";
				private String strRemark = "";
				private boolean bGenerateProteinFile = false;
				private boolean bPeptideDB = false;
			}
		}
	}
}
